package com.pro.staffmanage.security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Map;

public class StaffManagerVerifyFilter extends UsernamePasswordAuthenticationFilter {

    private static final String FORM_VERIFY_KEY = "userVerifyCode";

    private String verifyCode = FORM_VERIFY_KEY;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        System.out.println("=========================================");
        //  1.判断是否为POST请求
        if (!(HttpMethod.POST.name()).equals(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //  2.验证验证码
        //  如果是保存到redis中的, 则用redis的方法取
        HttpSession session = request.getSession();
        String verifyCode = (String)session.getAttribute("verifyCode");
        String verifyUser ;
        //  3.从json获取登录数据
        if (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
            try {
                //  将前端传来的json数据处理为map以供使用
                Map<String, String> mapper = new ObjectMapper().readValue(request.getInputStream(), Map.class);
                String username = mapper.get(this.getUsernameParameter());
                username = (username != null) ? username.trim() : "";
                String password = mapper.get(this.getPasswordParameter());
                password = (password != null) ? password : "";
                //  对验证码处理
                verifyUser = mapper.get(this.getVerifyCode());
                checkVerifyCode(verifyUser, verifyCode, session);
                //  对rememberMe进行处理
                String rememberMe = mapper.get(AbstractRememberMeServices.DEFAULT_PARAMETER);
                if( !ObjectUtils.isEmpty(rememberMe) ){
                    //  因为这个 filter 会比 service 先执行, 而 service 又会获得 request, 因此可以先存到 request 中
                    request.setAttribute(AbstractRememberMeServices.DEFAULT_PARAMETER, rememberMe);
                }
                UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
                        password);
                // Allow subclasses to set the "details" property
                this.setDetails(request, authRequest);
                System.out.println("用json格式登录成功");
                //  4.数据带给getAuthenticationManager() -- ProviderManager去认证
                return this.getAuthenticationManager().authenticate(authRequest);
            } catch (IOException e) {
                logger.info("用户名或密码输入类型不是json:\t" + e.getMessage());
            }
        }
        else {
            verifyUser = request.getParameter(this.getVerifyCode());
            checkVerifyCode(verifyUser, verifyCode, session);
        }
        //  3.数据不为json则按原方法处理
        return super.attemptAuthentication(request, response);
    }

    public String getVerifyCode() {
        return this.verifyCode;
    }

    public void setVerifyCode(String verifyCode) {
        this.verifyCode = verifyCode;
    }

    public void checkVerifyCode(String verifyUser, String verifyCode, HttpSession session){
        if ( verifyCode == null || !verifyCode.equalsIgnoreCase(verifyUser) ) {
            AuthenticationServiceException exception = new AuthenticationServiceException("验证码不正确请重新输入");
            System.out.println("verifyUser: "+verifyUser + " ===== verifyCode: " + verifyCode);
            session.setAttribute("verifyException", exception);
            throw exception;
        }
        System.out.println("Verify Success!");
    }

}
